package cn.jinjimi.app.custom.manager;

import cn.jinjimi.base.preference.PreferenceManager;
import cn.jinjimi.base.util.GsonUtils;
import cn.jinjimi.base.util.StringUtils;
import cn.jinjimi.app.AccountManager;
import cn.jinjimi.app.controller.BaseController;
import cn.jinjimi.app.controller.CommonController;
import cn.jinjimi.app.controller.CustomerController;
import cn.jinjimi.app.controller.event.DataEvent;
import cn.jinjimi.app.controller.event.LocalEvent.CustomLasteFollowRefreshEvent;
import cn.jinjimi.app.controller.event.UploadContactStateEvent;
import cn.jinjimi.app.controller.event.UploadResultEvent;
import cn.jinjimi.app.custom.entity.Custom;
import cn.jinjimi.app.custom.entity.CustomCount;
import cn.jinjimi.app.custom.entity.CustomFollowsDTO;
import cn.jinjimi.app.custom.entity.CustomListBean;
import cn.jinjimi.app.custom.entity.CustomListDTO;
import cn.jinjimi.app.custom.entity.SearchCustomerResult;
import cn.jinjimi.app.custom.entity.UploadCustom;
import cn.jinjimi.app.custom.event.CustomAvatarUploadEvent;
import cn.jinjimi.app.custom.event.CustomCountEvent;
import cn.jinjimi.app.custom.event.CustomDelEvent;
import cn.jinjimi.app.custom.event.CustomFollowRecordEvent;
import cn.jinjimi.app.custom.event.CustomGetInfoEvent;
import cn.jinjimi.app.custom.event.CustomInfoEvent;
import cn.jinjimi.app.custom.event.CustomTypeEvent;
import cn.jinjimi.app.custom.event.CustomTypeListEvent;
import cn.jinjimi.app.custom.event.CustomTypeTopEvent;
import cn.jinjimi.app.custom.event.CustomerListChangeEvent;
import cn.jinjimi.app.custom.event.CustomerSearchEvent;
import cn.jinjimi.app.custom.utils.LetterUtil;
import cn.jinjimi.domain.data.dto.CustomErrorDTO;
import cn.jinjimi.domain.data.dto.CustomImportDTO;
import cn.jinjimi.domain.data.dto.CustomerDto;
import cn.jinjimi.domain.ServiceManager;
import cn.jinjimi.domain.store.CustomerStore;
import cn.jinjimi.app.store.DatabaseManager;
import cn.jinjimi.app.store.dao.ContactInfoDao;
import cn.jinjimi.app.store.entity.custom.ContactInfo;
import cn.jinjimi.app.store.entity.custom.LastFollow;
import cn.jinjimi.app.util.AddressUtils;
import cn.jinjimi.app.bean.SharePrefKeys;

import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;

import bolts.Continuation;
import bolts.Task;
import retrofit2.Response;

/**
 * 客户管理
 * <p/>
 * Created by jinsen on 15/10/13.
 */
public class CustomsManager {

    private boolean mLoadCustomsDone = false;//是否加载完客户

    private List<Custom> mCustomsList;//全部客户列表
    private long mLastModify = 0;
    private CustomCount mCustomCount;

    private static volatile CustomsManager _instance;

    public static CustomsManager getInstance() {
        if (_instance == null) {
            synchronized (CustomsManager.class) {
                if (_instance == null)
                    _instance = new CustomsManager();
            }
        }
        return _instance;
    }

    private CustomsManager() {
        mCustomsList = new ArrayList<>();
        initCustoms();
    }

    public void logout() {
        getCustomsList().clear();
        mCustomCount = null;
        postListChangeEvent(CustomerListChangeEvent.StateLogOut);
        _instance = null;
    }

    /* 初始化客户数据 */
    public void initCustoms() {
        if (!AccountManager.getInstance().isLogin())
            return;

        mLastModify = PreferenceManager.getLongData(SharePrefKeys.PREF_CUSTOMS_LAST_MODIFY + AccountManager.getInstance().getAccount().ssoid);

        mLoadCustomsDone = false;

        Task.callInBackground(new Callable<List<Custom>>() {
            @Override
            public List<Custom> call() throws Exception {
                loadCustomFromCache();
                postListChangeEvent(CustomerListChangeEvent.StateCacheSuc);

                mLoadCustomsDone = true;
                loadCustomFromNet();
                return null;
            }
        });
    }

    /**
     * 外部调用 获取客户数据
     */
    public void getCustoms() {
        if (!AccountManager.getInstance().isLogin())
            return;

        if (mLoadCustomsDone) {
            postListChangeEvent(CustomerListChangeEvent.StateCacheSuc);
            loadCustomFromNet();
        }
    }

    /* 从本地数据库获取数据 */
    private void loadCustomFromCache() {
        getCustomsList().clear();
        List<Custom> customs = DatabaseManager.getInstance().getCustomerDao().queryBySsoid();
        getCustomsList().addAll(customs);
        if (getCustomsList().isEmpty()) {
            setLastModify(0);
        }
    }

    /* 从网络获取最新客户数据 */
    private void loadCustomFromNet() {
        CustomerController.getCustomList(getLastModify()).continueWith(new Continuation<CustomListDTO, Object>() {
            @Override
            public Object then(Task<CustomListDTO> task) throws Exception {
                CustomListDTO dto = task.getResult();
                if (dto != null && dto.data != null) {
                    CustomListBean bean = dto.data;

                    /* 存储客户各种数量数据 */
                    getCustomCount().setCustomCount(new CustomCount(bean.clueCount, bean.contractCount, bean.potentialCount, bean.recentCount));
                    EventBus.getDefault().post(new CustomCountEvent());

                    /* 设置最后一次刷新时间 */
                    setLastModify(bean.lastModified);

                    /* 添加或存储本地数据库 */
                    addOrUpdateCustoms(bean.customers);
                } else {// 网路请求失败直接返回数据库数据
                    postListChangeEvent(CustomerListChangeEvent.StateNetFail);
                }

                return null;
            }
        });
    }

    /* 增加或修改一组Custom数据 */
    private synchronized void addOrUpdateCustoms(List<Custom> customs) {
        Task.forResult(customs).continueWith(new Continuation<List<Custom>, Void>() {
            @Override
            public Void then(Task<List<Custom>> task) throws Exception {
                if (task.getResult() == null || task.getResult().isEmpty()) {
                    if (getCustomsList().isEmpty())
                        postListChangeEvent(CustomerListChangeEvent.StateNetSuc);
                    else
                        postListChangeEvent(CustomerListChangeEvent.StateNetEmpty);
                    return null;
                }

                DatabaseManager.getInstance().getCustomerDao().insertOrUpdate(task.getResult());
                loadCustomFromCache();
                postListChangeEvent(CustomerListChangeEvent.StateNetSuc);

                return null;
            }
        }, Task.BACKGROUND_EXECUTOR);
    }

    /**
     * 更新一个客户
     *
     * @param custom
     * @param avatarPath
     */
    public synchronized void updateCustom(Custom custom, final String avatarPath) {
        saveCustom(custom, avatarPath, null);
    }

    /**
     * 新增一个客户
     *
     * @param custom
     * @param avatarPath
     * @param clueId
     */
    public synchronized void addCustom(Custom custom, final String avatarPath, String clueId) {
        saveCustom(custom, avatarPath, clueId);
    }

    private synchronized void saveCustom(Custom custom, final String avatarPath, String clueId) {
        CustomerController.addOrUpdateCustom(custom, clueId).continueWith(new Continuation<Response<CustomerDto>, Custom>() {
            @Override
            public Custom then(Task<Response<CustomerDto>> task) throws Exception {
                Response<CustomerDto> response = task.getResult();
                if (response == null) {
                    EventBus.getDefault().post(new CustomInfoEvent(DataEvent.FAIL));
                    return null;
                }

                if (response.isSuccessful()) {
                    CustomerDto dto = response.body();
                    if (dto != null && dto.customer != null)
                        return dto.customer;
                }

                try {
                    CustomErrorDTO errorDTO = GsonUtils.fromJson(response.errorBody().string(), CustomErrorDTO.class);
                    EventBus.getDefault().post(new CustomInfoEvent(DataEvent.FAIL, errorDTO.message));
                    return null;
                } catch (IOException e) {
                    e.printStackTrace();
                }

                EventBus.getDefault().post(new CustomInfoEvent(DataEvent.FAIL));
                return null;
            }
        }).continueWith(new Continuation<Custom, Custom>() {// 处理头像上传
            @Override
            public Custom then(Task<Custom> task) throws Exception {
                if (task.getResult() != null) {
                    if (StringUtils.isNotEmpty(avatarPath)) {
                        UploadResultEvent event = CommonController.uploadCustomFile(task.getResult().customerId, avatarPath);
                        if (event != null && event.state == DataEvent.SUCC) {
                            task.getResult().avatar = "file://" + avatarPath;
                            EventBus.getDefault().post(new CustomAvatarUploadEvent(DataEvent.SUCC));
                        } else {
                            EventBus.getDefault().post(new CustomAvatarUploadEvent(DataEvent.FAIL));
                        }
                    }
                    return task.getResult();
                } else {
                    return null;
                }
            }
        }).continueWith(new Continuation<Custom, Void>() {// 存储数据库
            @Override
            public Void then(Task<Custom> task) throws Exception {
                if (task.getResult() != null) {
                    DatabaseManager.getInstance().getCustomerDao().insertOrUpdate(task.getResult());
                    loadCustomFromCache();
                    EventBus.getDefault().post(new CustomInfoEvent(DataEvent.SUCC, task.getResult()));
                }
                return null;
            }
        });
    }

    /**
     * 从通讯录上传客户
     *
     * @param customs
     */
    public synchronized void uploadCustoms(List<Custom> customs) {
        Task.forResult(customs).continueWith(new Continuation<List<Custom>, List<UploadCustom>>() {
            @Override
            public List<UploadCustom> then(Task<List<Custom>> task) throws Exception {
                EventBus.getDefault().post(new UploadContactStateEvent(UploadContactStateEvent.STATE.LOAD_START));

                List<UploadCustom> shouldUpload = new ArrayList<>();
                String agentId = AccountManager.getInstance().getAccount().ssoid;
                for (Custom c : task.getResult()) {
                    UploadCustom item = new UploadCustom();
                    item.agent_id = agentId;
                    item.real_name = c.name;
                    item.birthday = c.birthday;
                    item.birthType = "1";
                    File header = AddressUtils.getFileImage(c.contanct_id);
                    if (header != null) {
                        item.fileName = header.getName();
                        item.headerImg = header;
                    }

                    //允许导入电话号码则取联系人的电话列表
                    item.phones = c.getContactInfos();
                    item.source = BaseController.SOURCE_CONTACTS;
                    item.remark = c.remark;
                    item.address = c.address;
                    //把需要导入的客户加入应导入链表
                    shouldUpload.add(item);
                }
                //读取通讯录结束
                EventBus.getDefault().post(new UploadContactStateEvent(UploadContactStateEvent.STATE.LOAD_END));
                //有需要导入的客户，同时也上传一份到服务器
                if (shouldUpload.isEmpty()) {
                    EventBus.getDefault().post(new UploadContactStateEvent(UploadContactStateEvent.STATE.NOTHING_UPLOAD));
                    return null;
                }

                return shouldUpload;
            }
        }, Task.BACKGROUND_EXECUTOR).continueWith(new Continuation<List<UploadCustom>, CustomImportDTO>() {
            @Override
            public CustomImportDTO then(Task<List<UploadCustom>> task) throws Exception {
                if (task.getResult() != null && !task.getResult().isEmpty()) {
                    EventBus.getDefault().post(new UploadContactStateEvent(UploadContactStateEvent.STATE.UPLOAD_START));

                    CustomImportDTO dto = ServiceManager.getService(CustomerStore.class).importContacts(task.getResult());
                    if (dto != null && dto.isOk && dto.customers != null) {
                        /* 添加或存储本地数据库 */
                        addOrUpdateCustoms(dto.customers);

                        EventBus.getDefault().post(new UploadContactStateEvent(UploadContactStateEvent.STATE.UPLOAD_SUCC, dto));
                    } else {
                        EventBus.getDefault().post(new UploadContactStateEvent(UploadContactStateEvent.STATE.UPLOAD_FAIL));
                    }

                }
                return null;
            }
        });
    }

    /**
     * 修改客户置顶状态
     *
     * @param custom
     */
    public synchronized void updateTopState(Custom custom) {
        Task.forResult(custom).continueWith(new Continuation<Custom, Void>() {
            @Override
            public Void then(Task<Custom> task) throws Exception {
                DatabaseManager.getInstance().getCustomerDao().updateTopState(task.getResult().customerId,
                        task.getResult().top, task.getResult().topTime);
                EventBus.getDefault().post(new CustomTypeTopEvent());
                return null;
            }
        }, Task.BACKGROUND_EXECUTOR);
    }

    /**
     * 修改客户状态
     *
     * @param customId
     * @param type
     */
    public synchronized void updateCustomType(long customId, int type) {
        CustomerController.updateCustomType(customId, type).continueWith(new Continuation<CustomerDto, Object>() {
            @Override
            public Object then(Task<CustomerDto> task) throws Exception {
                CustomerDto dto = task.getResult();
                if (dto != null && dto.customer != null) {
                    dto.customer.initPingyingName();

                    DatabaseManager.getInstance().getCustomerDao().insertOrReplaceInTx(dto.customer);//  不用insertOrUpdate方式是因为需要清空原来的指定状态，网络放回的数据正好是空的，所以可以直接插入数据库
                    Custom custom = DatabaseManager.getInstance().getCustomerDao().load(dto.customer.customerId);
                    EventBus.getDefault().post(new CustomTypeEvent(custom, DataEvent.SUCC));
                } else {
                    EventBus.getDefault().post(new CustomTypeEvent(DataEvent.FAIL));
                }
                return null;
            }
        });
    }

    /**
     * 删除客户
     *
     * @param custom
     * @param directDel 是否需要请求服务器 还是直接删除本地
     */
    public synchronized void deleteCustom(final Custom custom, boolean directDel) {
        if (directDel) {
            deleCustom(custom);
        } else {
            CustomerController.deleteCustom(custom.customerId).continueWith(new Continuation<CustomerDto, Void>() {
                @Override
                public Void then(Task<CustomerDto> task) throws Exception {
                    CustomerDto dto = task.getResult();
                    if (dto != null && dto.customer != null) {
                        Custom custom1 = dto.customer;
                        deleCustom(custom1);
                    } else {
                        EventBus.getDefault().post(new CustomDelEvent(DataEvent.FAIL));
                    }

                    return null;
                }
            });
        }
    }

    private void deleCustom(Custom custom) {
        Task.forResult(custom).continueWith(new Continuation<Custom, Void>() {
            @Override
            public Void then(Task<Custom> task) throws Exception {
                if (task.getResult() == null)
                    return null;

                for (Custom cus : getCustomsList()) {
                    if (cus.customerId.equals(task.getResult().customerId)) {
                        getCustomsList().remove(cus);
                        List<Custom> newCustomList = getCustomsList();
                        getCustomsList().clear();
                        getCustomsList().addAll(newCustomList);
                        break;
                    }
                }

                DatabaseManager.getInstance().getCustomerDao().delete(task.getResult().customerId);
                EventBus.getDefault().post(new CustomDelEvent(DataEvent.SUCC));
                postListChangeEvent(CustomerListChangeEvent.StateDel);

                return null;
            }
        });
    }

    /**
     * 获取客户信息
     *
     * @param customId
     */
    public synchronized void getCustomInfo(final long customId) {
        CustomerController.getCustomInfo(customId).continueWith(new Continuation<Response<CustomerDto>, Void>() {
            @Override
            public Void then(Task<Response<CustomerDto>> task) throws Exception {
                Response<CustomerDto> response = task.getResult();
                if (response == null) {
                    EventBus.getDefault().post(new CustomGetInfoEvent(DatabaseManager.getInstance().getCustomerDao().loadDeepCustomById(customId), DataEvent.FAIL));
                    return null;
                }

                if (response.isSuccessful()) {
                    CustomerDto dto = response.body();
                    if (dto != null && dto.customer != null) {
                        dto.customer.initPingyingName();

                        DatabaseManager.getInstance().getCustomerDao().insertOrUpdate(dto.customer);
                        dto.customer.__setDaoSession(DatabaseManager.getInstance().getCustomerDao().returnDaoSession());

                        EventBus.getDefault().post(new CustomGetInfoEvent(dto.customer, DataEvent.SUCC));
                    } else {
                        EventBus.getDefault().post(new CustomGetInfoEvent(DataEvent.SUCC));
                    }
                } else {
                    EventBus.getDefault().post(new CustomGetInfoEvent(DatabaseManager.getInstance().getCustomerDao().loadDeepCustomById(customId), DataEvent.FAIL));
                }
                return null;
            }
        });
    }

    /**
     * 获取客户跟进记录列表
     *
     * @param customId
     */
    public synchronized void getCustomFollows(final long customId) {
        CustomerController.getFollowList(customId).continueWith(new Continuation<CustomFollowsDTO, Void>() {
            @Override
            public Void then(Task<CustomFollowsDTO> task) throws Exception {
                CustomFollowsDTO dto = task.getResult();
                if (dto != null) {
                    Custom mCustom = DatabaseManager.getInstance().getCustomerDao().loadDeepCustomById(customId);

                    mCustom.setLastFollow(LastFollow.transferFollow((dto.follows == null || dto.follows.isEmpty()) ? null : dto.follows.get(0)));

                    DatabaseManager.getInstance().getLastFollowDao().clearLastFollowByCustomId(mCustom.customerId);
                    if (mCustom.lastFollow != null) {
                        DatabaseManager.getInstance().getLastFollowDao().insertOrReplaceInTx(mCustom.lastFollow);
                    }

                    DatabaseManager.getInstance().getCustomerDao().insertOrUpdate(mCustom);

                    EventBus.getDefault().post(new CustomLasteFollowRefreshEvent());

                    EventBus.getDefault().post(new CustomFollowRecordEvent(dto, DataEvent.SUCC));
                } else {
                    EventBus.getDefault().post(new CustomFollowRecordEvent(DataEvent.FAIL));
                }
                return null;
            }
        });
    }

    /* 客户列表发送改变 */
    private void postListChangeEvent(int state) {
        if (state == CustomerListChangeEvent.StateCacheSuc && getCustomsList().isEmpty())
            return;

        EventBus.getDefault().post(new CustomerListChangeEvent(state));
    }

    /**
     * 根据手机号码搜索相应手机号码客户，异步返回，需注册CustomerSearchEvent事件获取结果
     * <p>
     * 根据手机号码查询拥有相同手机号码的客户list
     *
     * @param phone
     */
    public void searchCustomertWithPhone(String phone) {
        Task.forResult(phone).continueWith(new Continuation<String, Void>() {
            @Override
            public Void then(Task<String> task) throws Exception {
                String phone = task.getResult();
                if (phone == null)
                    phone = "";

                List<ContactInfo> results = DatabaseManager.getInstance().getContactInfoDao().queryBuilder()
                        .where(ContactInfoDao.Properties.Value.eq(phone))
                        .where(ContactInfoDao.Properties.SsoId.eq(AccountManager.getInstance().getAccount().ssoid))
                        .list();

                List<Custom> mList = new ArrayList<>();
                if (StringUtils.isNotEmpty(phone)) {
                    for (ContactInfo contactInfo : results) {
                        Custom custom = contactInfo.getCustom();
                        if (custom != null) {
                            custom.initPingyingName();
                            mList.add(custom);
                        }
                    }
                }

                SearchCustomerResult mResult = new SearchCustomerResult(mList, phone);

                EventBus.getDefault().post(new CustomerSearchEvent(mResult));
                return null;
            }
        });
    }

    /**
     * 根据客户状态获取客户列表数据
     *
     * @param type
     */
    public void getCustomTypeList(final int type) {
        if (mLoadCustomsDone) {
            Task.callInBackground(new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    List<Custom> customs = DatabaseManager.getInstance().getCustomerDao().queryByType(type);
                    if (customs != null)
                        Collections.sort(customs, new LetterUtil.ComparatorTop());
                    EventBus.getDefault().post(new CustomTypeListEvent(customs));
                    return null;
                }
            });
        }
    }

    /* 获取内存缓存中的客户 */
    public synchronized List<Custom> getCustomsList() {
        return mCustomsList;
    }

    /* 获取存储客户各种数量数据 */
    public CustomCount getCustomCount() {
        if (mCustomCount == null)
            mCustomCount = CustomCount.getCacheCustomCount();
        return mCustomCount;
    }

    /* 设置最后一次修改时间 */
    private void setLastModify(long lastModify) {
        PreferenceManager.setData(SharePrefKeys.PREF_CUSTOMS_LAST_MODIFY + AccountManager.getInstance().getAccount().ssoid, lastModify);
        this.mLastModify = lastModify;
    }

    /* 获取最后一次刷新时间 */
    private long getLastModify() {
        if (mLastModify == 0)
            mLastModify = PreferenceManager.getLongData(SharePrefKeys.PREF_CUSTOMS_LAST_MODIFY + AccountManager.getInstance().getAccount().ssoid);

        return mLastModify;
    }

}